package uebung06_h;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.JFrame;

import tools.Arrow;

/**
 *
 * @author fwiesel
 */
public final class FieldModel {
	static final float FIELD_LENGTH = 0.95f*6.f;
	static final float FIELD_WIDTH = 0.95f*4.f;
	static final float LINE_WIDTH = 0.05f;
	static final float GOAL_AREA_DEPTH = 0.6f;
	static final float GOAL_AREA_WIDTH = 2.6f;
	static final float CENTRE_CIRCLE_RADIUS = 0.6f;
	static final float PENALTY_DIST = 1.8f;
	static final float HFW = 0.5f*FIELD_WIDTH;
	static final float HFL = 0.5f*FIELD_LENGTH;
	static final float HGW = 0.5f*GOAL_AREA_WIDTH;
	static final float GRIDY = 101, GRIDX = 71;
	
	public static void main(String... args) {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		final Rectangle2D rect = new Rectangle2D.Double();
		final Line2D line = new Line2D.Double();
		final Ellipse2D circle = new Ellipse2D.Double();
		
		final AffineTransform transform = AffineTransform.getScaleInstance(100, 100);
		
		transform.concatenate(AffineTransform.getTranslateInstance(3, 4));
		final ArrayList<Line2D> lines = new ArrayList<Line2D>();
		lines.clear();
		
		line.setLine(-FIELD_WIDTH/2., -FIELD_LENGTH/2., FIELD_WIDTH/2., -FIELD_LENGTH/2);
		lines.add(new Line2D.Double() {{setLine(line);}});

		line.setLine(-FIELD_WIDTH/2., FIELD_LENGTH/2., FIELD_WIDTH/2., FIELD_LENGTH/2);
		lines.add(new Line2D.Double() {{setLine(line);}});

		line.setLine(-FIELD_WIDTH/2., -FIELD_LENGTH/2., -FIELD_WIDTH/2., FIELD_LENGTH/2);
		lines.add(new Line2D.Double() {{setLine(line);}});

		line.setLine(FIELD_WIDTH/2., -FIELD_LENGTH/2., FIELD_WIDTH/2., FIELD_LENGTH/2);
		lines.add(new Line2D.Double() {{setLine(line);}});

		line.setLine(-FIELD_WIDTH/2., 0, FIELD_WIDTH/2., 0);
		lines.add(new Line2D.Double() {{setLine(line);}});

		line.setLine(-GOAL_AREA_WIDTH/2., -FIELD_LENGTH/2.+GOAL_AREA_DEPTH, GOAL_AREA_WIDTH/2., -FIELD_LENGTH/2.+GOAL_AREA_DEPTH);
		lines.add(new Line2D.Double() {{setLine(line);}});

		line.setLine(-GOAL_AREA_WIDTH/2., FIELD_LENGTH/2.-GOAL_AREA_DEPTH, GOAL_AREA_WIDTH/2., FIELD_LENGTH/2.-GOAL_AREA_DEPTH);
		lines.add(new Line2D.Double() {{setLine(line);}});
		
		line.setLine(-GOAL_AREA_WIDTH/2., -FIELD_LENGTH/2., -GOAL_AREA_WIDTH/2., -FIELD_LENGTH/2.+GOAL_AREA_DEPTH);
		lines.add(new Line2D.Double() {{setLine(line);}});
		
		line.setLine(GOAL_AREA_WIDTH/2., -FIELD_LENGTH/2, GOAL_AREA_WIDTH/2., -FIELD_LENGTH/2.+GOAL_AREA_DEPTH);
		lines.add(new Line2D.Double() {{setLine(line);}});

		line.setLine(-GOAL_AREA_WIDTH/2., FIELD_LENGTH/2., -GOAL_AREA_WIDTH/2., FIELD_LENGTH/2.-GOAL_AREA_DEPTH);
		lines.add(new Line2D.Double() {{setLine(line);}});
		
		line.setLine(GOAL_AREA_WIDTH/2., FIELD_LENGTH/2, GOAL_AREA_WIDTH/2., FIELD_LENGTH/2.-GOAL_AREA_DEPTH);
		lines.add(new Line2D.Double() {{setLine(line);}});
		
		circle.setFrameFromCenter(0, 0, CENTRE_CIRCLE_RADIUS, CENTRE_CIRCLE_RADIUS);
		
		final AffineTransform zoom = new AffineTransform();

		final JComponent canvas = new JComponent() {
			{setPreferredSize(new Dimension(600,800));}
			public void paint(java.awt.Graphics g) {
				
				Graphics2D g2 = (Graphics2D)g;
				
				g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
				g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
				g2.transform(transform);

				g2.setStroke(new BasicStroke(LINE_WIDTH));
				
				for (Line2D l : lines) {
					g2.draw(l);
				}
				
				g2.draw(circle);
				

			};
		};
		
		final float FIELD_SIZEX = 5f, FIELD_SIZEY = 7f;

		final JComponent vektorfeld = new JComponent() {
			{setPreferredSize(new Dimension(600,800));}
			
			Arrow arrw = new Arrow();
			Line helper = new Line();
			Circle helperc = new Circle(); 
			@Override
			public void paint(Graphics g) {
				Graphics2D g2 = (Graphics2D)g;
				
				g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
				g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

				g2.setStroke(new BasicStroke(0.005f));

				g2.transform(zoom);
				g2.transform(transform);
				g2.setColor(Color.red);
				for (Line2D l : lines) {
					g2.draw(l);
				}
				
				g2.draw(circle);
				g2.setColor(Color.green);
				for (double y = 0; y<GRIDY; y+=1) {
					for (double x = 0; x<GRIDX; x+=1) {
						
						double realx = (FIELD_SIZEX/70.)*(x-35.), realy = (FIELD_SIZEY/100.)*(y-50.);
						double min = Double.POSITIVE_INFINITY;
						Point2D from = new Point2D.Double(realx, realy), to = null;
						Line2D minline = null;
						
						for (Line2D l : lines) {
							helper.setLine(l);
							
							double newmin = helper.getDistance(realx, realy);
						
							if (min>newmin) {
								min = newmin;
								minline = l;
							}
						}
						helperc.setCircle(circle);
						Circle hc = null;
						if (min>helperc.getDistance(realx, realy)) {
							hc = helperc;
						}
						if (hc==null) {
							
							helper.setLine(minline);
							to = helper.getNearest(realx, realy); 
						}
						else {
							to = helperc.getNearest(realx, realy);
						}
						arrw.setArrow(from, to, 0.015, 0.025);
//						System.out.println("from: "+from+" -> \t"+to);
						g2.setColor(Color.magenta);
						g2.fill(arrw);
						g2.setColor(Color.green);
						g2.draw(arrw);
							
					}
				}
				super.paint(g);
			}
		};
		vektorfeld.addMouseWheelListener(new MouseWheelListener() {
			
			@Override
			public void mouseWheelMoved(MouseWheelEvent e) {
				
				double scale = Math.pow(1.01, e.getWheelRotation());

				try {
					Point2D p = new Point2D.Double(e.getX(), e.getY()); 
					zoom.inverseTransform(p, p);
					zoom.concatenate(AffineTransform.getTranslateInstance(p.getX(), p.getY()));
					zoom.concatenate(AffineTransform.getScaleInstance(scale, scale));
					zoom.concatenate(AffineTransform.getTranslateInstance(-p.getX(), -p.getY()));
				}
				catch (NoninvertibleTransformException nte ) {
					nte.printStackTrace();
				}
				vektorfeld.repaint();
			}
		});
		frame.add(canvas, BorderLayout.EAST);
		frame.add(vektorfeld, BorderLayout.CENTER);
		frame.pack();
		frame.setVisible(true);
		
	}
	
}
